package algoritmo;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Random;

public class Nodo {
	
	String dato;
	Nodo izq;
	Nodo central;
	Nodo der;
	
	int numNodos;
	int nivel;
	
	static Nodo nodoBuscado;// para que aunque lo llames con izq.buscaNodoRec, tenga el mismo valor que en el padre, porque si no los hijos no lo tienen y tienes 0
	static int nodoCruce;// para que aunque lo llames con izq.buscaNodoRec, tenga el mismo valor que en el padre, porque si no los hijos no lo tienen y tienes 0

	String[] operadores = {"EQ", "IF", "PROGN2", "PROGN3"};
	String[] terminales = {"izquierda", "derecha", "fuego", "distY", "distX"};
	
	static ArrayList<Nodo> array = new ArrayList<Nodo>();
	
//	int profMin,profMax;
	
	public Nodo(){
		dato = "";
		izq = null;
		central = null;
		der = null;	
		numNodos = 0;
		
		nodoBuscado=null;
		nodoCruce=0;
	}
	
	public void asignaOperador(String dato){
		this.dato = dato;
	}
	
	public void asignaHijoDer(Nodo n){
		this.der = n;
		numNodos++;
	}
	
	public void asignaHijoIzq(Nodo n){
		this.izq = n;
		numNodos++;
	}
	
	public void asignaHijoCentr(Nodo n){
		this.central = n;
		numNodos++;
	}
	
	public boolean esHoja(){
		return (izq==null && der==null && central==null);
	}
	
	public void creaArbolCompleta(int prof,int profMaxima) {
		
		if(prof < profMaxima){
			Random r = new Random();
			
			String operacion = operadores[r.nextInt(4)];
			dato = operacion;
			nivel=prof;
			
			//Generamos los hijos
			izq = new Nodo();
			izq.creaArbolCompleta(prof+1,profMaxima);
			numNodos += izq.numNodos; 
			
			if(operacion == "PROGN3" || operacion == "IF"){
				central = new Nodo();
				central.creaArbolCompleta(prof+1,profMaxima);
				numNodos += central.numNodos; 
			}
			
			der = new Nodo();
			der.creaArbolCompleta(prof+1,profMaxima);
			numNodos += der.numNodos; 
			
			numNodos+=1;
			
		}else{
			Random r = new Random();
			
			String terminal = terminales[r.nextInt(5)]; 
			dato = terminal;
			numNodos += 1;
			nivel=prof;
		}
	}
	
	public void creaArbolCreciente(int prof,int profMaxima) {
		
		if(prof < profMaxima){
			Random r = new Random();
			
			if(r.nextBoolean()){//Si sale true es una funcion
				String operacion = operadores[r.nextInt(4)];
				dato = operacion;
				nivel=prof;
				
				//Generamos los hijos
				izq = new Nodo();
				izq.creaArbolCreciente(prof+1,profMaxima);
				numNodos += izq.numNodos; 
				
				if(operacion == "PROGN3" || operacion == "IF"){
					central = new Nodo();
					central.creaArbolCreciente(prof+1,profMaxima);
					numNodos += central.numNodos; 
				}
				
				der = new Nodo();
				der.creaArbolCreciente(prof+1,profMaxima);
				numNodos += der.numNodos; 
				
				numNodos+=1;
				
			}else{//Si no, es un terminal
				String terminal = terminales[r.nextInt(5)];
				dato = terminal;
				nivel=prof;
				numNodos += 1;				
			}
			
		}else{
			Random r = new Random();
			
			String terminal = terminales[r.nextInt(5)]; 
			dato = terminal;
			numNodos += 1;
		}
	}
	
	
//	public void creaArbol(int profMin, int profMax) {
//		
//		if(profMin > 0){//Es subarbol de operador
//			generarSubarbolOperador(profMin, profMax);
//			
//		}else{//Generamos el terminal
//			if(profMax == 0){//Solo pueden ser hojas
//				generarSubarbolTerminal(profMin, profMax);
//			}else{//Puede ser terminal u operador
//				Random r = new Random();
//				boolean tipo = r.nextBoolean();
//				
//				if(tipo)
//					generarSubarbolOperador(profMin, profMax);
//				else
//					generarSubarbolTerminal(profMin, profMax);
//			}
//		}
//	}
////	
//	public void generarSubarbolOperador(int profMin, int profMax){
//		Random r = new Random();
//		
//		String operacion = operadores[r.nextInt(4)];
//		dato = operacion;
//		
//		//Generamos los hijos
//		izq = new Nodo();
//		izq.creaArbol(profMin-1, profMax-1);
//		numNodos += izq.numNodos; 
//		
//		if(operacion == "PROGN3" || operacion == "IF"){
//			central = new Nodo();
//			central.creaArbol(profMin-1, profMax-1);
//			numNodos += central.numNodos; 
//		}
//		
//		der = new Nodo();
//		der.creaArbol(profMin-1, profMax-1);
//		numNodos += der.numNodos; 
//		
//		numNodos+=1;
//	}
//	
//	public void generarSubarbolTerminal(int profMin, int profMax){
//		Random r = new Random();
//		
//		String terminal = terminales[r.nextInt(5)]; 
//		dato = terminal;
//		numNodos += 1;
//	}
	
	public Nodo buscaNodo(int nCruce){
		nodoCruce=nCruce;
		nodoBuscado=null;
		buscaNodoRec();
		return nodoBuscado;
	}
	
	// funciona
	public void buscaNodoRec(){
		if(nodoCruce==0)
			nodoBuscado = this;
		else{
			if(nodoBuscado==null && izq!=null){
				nodoCruce--;
				izq.buscaNodoRec();
			}
			if(nodoBuscado==null && central!=null){
				nodoCruce--;
				central.buscaNodoRec();
			}
			if(nodoBuscado==null && der!=null){
				nodoCruce--;
				der.buscaNodoRec();
			}
		}
	}
	
	public void sustituirArbol(int nodo, Nodo arbol){
		Nodo aSustituir = buscaNodo(nodo);
		
		aSustituir.central=arbol.central;
		aSustituir.der=arbol.der;
		aSustituir.izq=arbol.izq;
		aSustituir.dato=arbol.dato;
		aSustituir.numNodos=arbol.numNodos;
		
	}

	public void cambiarOperando() {
		Random r = new Random();
		dato = terminales[r.nextInt(5)];
	}

	public boolean cambiarOperador(int profundidad) {
		boolean ampliado=false;
		Random r = new Random();
		String antiguo = this.dato;
		String nuevo = operadores[r.nextInt(4)];
		if( (nuevo == "PROGN3" || nuevo == "IF") && (antiguo != "PROGN3" || antiguo!="IF") ){
			central = new Nodo();
			central.creaArbolCreciente(nivel+1, profundidad);
			ampliado=true;
			
		}else if( (antiguo == "PROGN3" || antiguo == "IF") && (nuevo != "PROGN3" || nuevo != "IF")){
			this.central=null;
		}
		
		this.dato=nuevo;
		return ampliado;
	}
	
	public void copiaGenes(Nodo antiguo) {
		if(antiguo!=null){
			numNodos = antiguo.numNodos;
			nivel = antiguo.nivel;
			this.dato=antiguo.dato;
			if(antiguo.izq!=null){
				this.izq=new Nodo();
				this.izq.copiaGenes(antiguo.izq);
			}
			if(antiguo.central!=null){
				this.central=new Nodo();
				this.central.copiaGenes(antiguo.central);
			}
			if(antiguo.der!=null){
				this.der=new Nodo();
				this.der.copiaGenes(antiguo.der);
			}
		}
	}

	// Funciona
	public void recontarNodos() {
		// Los pones todos a cero para que lo haga bien y recuentas desde el principio
		ponerACero();
		contarDeNuevo();
	}
	
	private void ponerACero() {
		if(izq!=null)
			izq.ponerACero();
		
		if(central!=null)
			central.ponerACero();
		
		if(der!=null)
			der.ponerACero();
		
		numNodos=0;
		
	}

	public void contarDeNuevo(){
	if(esHoja())
			numNodos += 1;
		else{
			if(izq!=null){
				izq.recontarNodos();
				numNodos += izq.numNodos;
			}
			if(central!=null){
				central.recontarNodos();
				numNodos += central.numNodos;
			}
			if(der!=null){
				der.recontarNodos();
				numNodos += der.numNodos;
			}
			numNodos++;
		}
	}
	
//	public void pintar(){
//		array.add(this);
//		pintarRec();
//	}
	
	public void pintarRec(){
		int nodos = array.size();
//		int numHijos=0;
//		if(array.get(0).izq!=null)
//			numHijos++;
//		if(array.get(0).central!=null)
//			numHijos++;
//		if(array.get(0).der!=null)
//			numHijos++;
		System.out.print("Nivel: "+array.get(0).nivel+" "+array.get(0).dato +"("+array.get(0).numNodos+")"+" ");
		array.remove(0);
		if(izq!=null)
			array.add(izq);
		if(central!=null)
			array.add(central);
		if(der!=null)
			array.add(der);
		
		System.out.println();
		if(array.size() > 0)
			array.get(0).pintarRec();
	}

	public void crearArbolDePrueba() {
		// El primero del ejemplo de la practica
		
		izq=new Nodo();
		central=new Nodo();
		der=new Nodo();
		
		izq.izq=new Nodo();
		izq.der=new Nodo();
		izq.izq.izq=new Nodo();
		izq.izq.central=new Nodo();
		izq.izq.der=new Nodo();
		
		izq.der.izq=new Nodo();
		izq.der.central=new Nodo();
		izq.der.der=new Nodo();
		
		central.izq=new Nodo();
		central.central=new Nodo();
		central.der=new Nodo();
		
		der.izq=new Nodo();
		der.central=new Nodo();
		der.der=new Nodo();
		
		der.central.izq=new Nodo();
		der.central.der=new Nodo();
		
		der.der.izq=new Nodo();
		der.der.central=new Nodo();
		der.der.der=new Nodo();
		
		dato="PROGN3";
		numNodos=23;
		
		izq.dato="EQ";
		izq.numNodos=9;
		
		central.dato="PROGN3";
		central.numNodos=4;
		
		der.dato="PROGN3";
		der.numNodos=9;
		
		izq.izq.dato="IF";
		izq.izq.numNodos=4;
		izq.der.dato="PROGN3";
		izq.der.numNodos=4;
		
		izq.izq.izq.dato="distX";
		izq.izq.izq.numNodos=1;
		izq.izq.central.dato="derecha";
		izq.izq.central.numNodos=1;
		izq.izq.der.dato="derecha";
		izq.izq.der.numNodos=1;
		
		izq.der.izq.dato="izquierda";
		izq.der.izq.numNodos=1;
		izq.der.central.dato="izquierda";
		izq.der.central.numNodos=1;
		izq.der.der.dato="distY";
		izq.der.der.numNodos=1;
		
		central.izq.dato="distY";
		central.izq.numNodos=1;
		central.central.dato="distX";
		central.central.numNodos=1;
		central.der.dato="distX";
		central.der.numNodos=1;
		
		der.izq.dato="fuego";
		der.izq.numNodos=1;
		der.central.dato="PROGN2";
		der.central.numNodos=3;
		der.der.dato="PROGN3";
		der.der.numNodos=4;
		
		der.central.izq.dato="izquierda";
		der.central.izq.numNodos=1;
		der.central.der.dato="izquierda";
		der.central.der.numNodos=1;
		
		der.der.izq.dato="izquierda";
		der.der.izq.numNodos=1;
		der.der.central.dato="derecha";
		der.der.central.numNodos=1;
		der.der.der.dato="izquierda";
		der.der.der.numNodos=1;
		
		
		
	}
	
	public void crearArbolDePrueba2() {
		izq=new Nodo();
		central=new Nodo();
		der=new Nodo();
		
		this.dato="PROGN3";
		
		izq.dato = "fuego";
		central.dato="distX";
		der.dato="derecha";
	
	}

	public void recalularNiveles(int niv) {
		nivel=niv;
		if(izq!=null)
			izq.recalularNiveles(niv+1);
		if(central!=null)
			central.recalularNiveles(niv+1);
		if(der!=null)
			der.recalularNiveles(niv+1);
				
	}

	/*
	 * (condicion)?(si_cierto):(si_falso)
	 */
	@Override
	public String toString() {
		String tabuladores = calculaTabuladores(nivel + 1);
		return (izq == null && central == null && der == null)?"[" + dato +"]":
			("[" + dato + "," + tabuladores + " HI=" + (izq != null?izq:"[]")
			+ "," + tabuladores + " HC=" + (central != null?central:"[]") + "," + tabuladores +" HD="
			+ (der != null?der:"[]") + "]");
	}


private String calculaTabuladores(int numero) {
		String tabuladores = "\n";
		for(int i = 0; i < numero; i++){
			tabuladores += "       ";
		}
		return tabuladores;
	}


	public int calcularProfundidadAlcanzada() {
	if(this.esHoja()){
		return 0;
	}else{
		if(central!=null)
			return 1+Math.max(izq.calcularProfundidadAlcanzada(), Math.max(central.calcularProfundidadAlcanzada(), der.calcularProfundidadAlcanzada()));
		else
			return 1+Math.max(izq.calcularProfundidadAlcanzada(),der.calcularProfundidadAlcanzada());
	}
	
}
	
	

	
}
